package com.zhtkj.util;

import java.util.List;

/** 
* @ClassName: GeoUtil 
* @Description: gps坐标工具类，计算距离、包含关系等等 
* @author mafeng 
* @date 2017年9月7日 上午9:52:59 
*  
*/
public class GeoUtil {

	private final static double PI = 3.14159265358979323; // 圆周率
	private final static double R = 6371229; // 地球的半径
	
	/**
	 * 检查多边形的List是否包含了某点~ true 为包含在内（边界上的不算）
	 * 
	 * @param ztGpsfenceList
	 *            电子围栏的ZtGpsfence集合
	 * @param lng  要判断坐标点的经度值
	 * @param lat  要判断坐标点的纬度值
	 * @return int
	 */
/*	public static int ztGpsfenceListContainsPointFenceId(List<ZtGpsfence> ztGpsfenceList, double lng,double lat){
		for(int i = 0; i < ztGpsfenceList.size(); i++){
			ZtGpsfence ztGpsfence = ztGpsfenceList.get(i);
			if(fencePosContainsPoint(ztGpsfence.getFencePos(),lng,lat)){
				return ztGpsfence.getFenceId();
			}
		}
		return 0;
	}*/
	/**
	 * 检查多边形的List是否包含了某点~ true 为包含在内（边界上的不算）
	 * 
	 * @param ztGpsfenceList
	 *            电子围栏的ZtGpsfence集合
	 * @param lng  要判断坐标点的经度值
	 * @param lat  要判断坐标点的纬度值
	 * @return boolean
	 */
/*	public static boolean ztGpsfenceListContainsPoint(List<ZtGpsfence> ztGpsfenceList, double lng,double lat){
		for(int i = 0; i < ztGpsfenceList.size(); i++){
			ZtGpsfence ztGpsfence = ztGpsfenceList.get(i);
			if(fencePosContainsPoint(ztGpsfence.getFencePos(),lng,lat)){
				return true;
			}
		}
		return false;
	}*/
	/**
	 * 检查多边形是否包含了某点~ true 为包含在内（边界上的不算）
	 * 
	 * @param fencePos
	 *            一连串的字符型坐标点，取自zhatu的zt_gps_fence里面的fencePos值
	 * @param lng  要判断坐标点的经度值
	 * @param lat  要判断坐标点的纬度值
	 * @return boolean
	 *//*
	public static boolean fencePosContainsPoint(String fencePos,double lng,double lat) {
		Point point = new Point(lng, lat);
		List<Point> polygon = new ArrayList();
		if (StringUtil.isNotEmpty(fencePos)) {
			String[] fencePosValueArray = fencePos.split(";");
			for (int i = 0; i < fencePosValueArray.length; i++) {
				Point pointPos = new Point(Double.valueOf(fencePosValueArray[i].split(",")[0]), Double.valueOf(fencePosValueArray[i].split(",")[1]));
				polygon.add(pointPos);
			}
		}
		return containsPoint(polygon, point);
	}*/

	/**
	 * 检查多边形是否包含了某点~ true 为包含在内（边界上的不算）
	 * 
	 * @param polygon 点集合的多边形
	 * @param point
	 * @return boolean
	 */
	public static boolean containsPoint(List<Point> polygon, Point point) {
		int polygonCount = polygon.size();
		// 多边形少于三个点，返回false
		if (polygonCount < 3) {
			return false;
		}
		int nCross = 0;
		for (int i = 0; i < polygon.size(); ++i) {
			Point p1 = polygon.get(i);
			Point p2 = polygon.get((i + 1) % polygonCount);
			// 求解 y=p.y 与 p1 p2 的交点
			if (p1.getLat() == p2.getLat()) { // p1p2 与 y=p0.y平行
				continue;
			}
			if (point.getLat() < Math.min(p1.getLat(), p2.getLat())) { // 交点在p1p2延长线上
				continue;
			}
			if (point.getLat() >= Math.max(p1.getLat(), p2.getLat())) { // 交点在p1p2延长线上
				continue;
			}
			// 求交点的 X 坐标
			double x = (point.getLat() - p1.getLat())
					* (p2.getLng() - p1.getLng()) / (p2.getLat() - p1.getLat())
					+ p1.getLng();
			if (x > point.getLng()) { // 只统计单边交点
				nCross++;
			}
		}
		// 单边交点为偶数，点在多边形之外
		return (nCross % 2 == 1);
	}


	/**
	 * 判断两个经纬度之间的距离是否在指定距离范围内，在范围内返回true
	 * 
	 * @param point1
	 *            第一个坐标点
	 * @param point2
	 *            第二个坐标点
	 * @param allowedDistance
	 *            指定距离范围
	 * @return boolean
	 */
	public static boolean allowedDistance(Point point1, Point point2,
			double allowedDistance) {
		double distance = getDistance(point1, point2);
		if (distance <= allowedDistance) {
			return true;
		} else {
			return false;
		}
	}
	

	/** 
	* @Title: getDistance 
	* @Description: 求2个坐标点之间的距离（单位：米） 
	* @param: @param point1 第一个坐标点
	* @param: @param point2 第二个坐标点
	* @param: @return 
	* @return double 
	* @throws 
	*/
	public static Double getDistance(Point point1, Point point2) {
		double x = (point2.getLng() - point1.getLng())
				* PI
				* R
				* Math.cos(((point1.getLat() + point2.getLat()) / 2) * PI / 180)
				/ 180;
		double y = (point2.getLat() - point1.getLat()) * PI * R / 180;
		double distance = Math.hypot(x, y);
		return distance;
	}
	
	/** 
	* @Title: getMinDistance 
	* @Description: 求坐标点和多边形之间的最短距离（单位：米） 
	* @param: point 第一个坐标点
	* @param: polygon 多边形坐标点集合
	* @return double 
	* @throws 
	*/
	public static Double getMinDistance(Point point, List<Point> polygon) {
		Double minDistance = getDistance(point, polygon.get(0));
		for (int i = 1; i < polygon.size(); i++) {
			Double distance = getDistance(point, polygon.get(i));
			if (distance < minDistance) {
				minDistance = distance;
			}
		}
		return minDistance;
	}
	
}
